package models;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.*;

import play.db.jpa.Model;
import play.modules.search.Field;
import play.modules.search.Indexed;

@Indexed
@Entity
@Table(name = "Components")
public class Component extends Model {

	@Field
	public String name;

	@Field
	public String description;

	@ManyToMany(mappedBy = "dependOnComponents")
	public List<UserStory> userStoriesDependant = new LinkedList<UserStory>();

	@ManyToOne
	public Project project;

	@OneToMany(mappedBy = "component", cascade = { CascadeType.REMOVE })
	public List<ComponentTaskTypeUser> taskTypeReviewers = new LinkedList<ComponentTaskTypeUser>();

	@OneToMany(mappedBy = "component", cascade = { CascadeType.REMOVE })
	public List<ComponentUser> user_components = new LinkedList<ComponentUser>();

	@OneToMany(mappedBy = "component")
	public List<UserStory> userStoriesAssigned = new LinkedList<UserStory>();

	/**
	 * constructs a new component and assigns it to a project.
	 * 
	 * @param name
	 * @param description
	 * @param project
	 */
	public Component(String name, String description, Project project) {
		super();
		this.name = name;
		this.description = description;
		this.project = project;
	}

	public Component delete() {
		for (UserStory story : userStoriesDependant) {
			story.dependOnComponents.remove(this);
			story.save();
		}
		Component defaultComponent = Component.find("byNameAndProject",
				"Default component", project).first();
		// If the default component exists and it is not this one
		if (defaultComponent != null && defaultComponent != this)
			for (UserStory story : userStoriesAssigned) {
				story.component = defaultComponent;
				story.save();
			}
		return super.delete();
	}

	/**
	 * This method returns a list of all Tasks in a certain component given the
	 * componentId
	 * 
	 * @param componentId
	 * 
	 * @return List<Task>
	 */
	public List<Task> getComponentTasks() {
		if (this == null)
			return null;

		List<UserStory> userStoriesList = this.userStoriesAssigned;
		if (userStoriesList == null)
			return new LinkedList<Task>();

		List<Task> tasksList = new LinkedList<Task>();

		for (int i = 0; i < userStoriesList.size(); i++)
			tasksList.addAll(userStoriesList.get(i).tasks);

		List<User> users = ComponentUser
				.find(
						"select cu.user from ComponentUser cu where cu.component =? and isMember=?",
						this, true).fetch();
		List<Task> tasksList2 = new LinkedList<Task>();
		for (int i = 0; i < users.size(); i++) {
			List<Task> tasks = new LinkedList<Task>();
			tasks = TaskUserUser
					.find(
							"select tuu.task from TaskUserUser tuu where tuu.assignee = ? and tuu.status = ?",
							users.get(i), true).fetch();
			for (int j = 0; j < tasks.size(); j++)
				if (this.getEntityId() == (Long) tasks.get(j)
						.getTaskComponent().getEntityId())
					tasksList2.add(tasks.get(j));
		}
		Set<Task> allTasks = new HashSet<Task>();
		allTasks.addAll(tasksList);
		allTasks.addAll(tasksList2);
		tasksList.clear();
		tasksList.addAll(allTasks);
		return tasksList;
	}

	/**
	 * This method returns a list of all Tasks in a certain component and a
	 * certain sprint given the componentIdand sprintId
	 * 
	 * @param componentId
	 * @param sprintId
	 * 
	 * @return List<Task>
	 */
	public List<Task> getComponentEventTasks(long sprintId) {
		Event sprint = Event.findById(sprintId);
		List<Task> sprintTasks = sprint.tasks;

		int i = 0;
		while (i < sprintTasks.size()) {
			if (sprintTasks.get(i).userStory != null)
				sprintTasks.remove(i);
			else
				i++;
		}

		i = 0;

		while (i < sprintTasks.size()) {
			if (sprintTasks.get(i).getTaskComponent() != null)
				if ((Long) sprintTasks.get(i).getTaskComponent().getEntityId() == (Long) this
						.getEntityId())
					i++;
				else
					sprintTasks.remove(i);
			else
				sprintTasks.remove(i);

		}

		return sprintTasks;

	}

}
